🐳 Docker 환경 전체 백업 & 복구 가이드
Docker 기반 멀티 서비스 환경에서 DB + Volume + 메타데이터 + 프로젝트 파일을 체계적으로 백업하고,
USB 외부 매체로 안전하게 옮기며, 필요 시 새 서버에서 완전 복구하는 방법을 정리합니다.
📑 목차
1. 백업 대상
2. 통합 백업 스크립트
3. 설정 & 실행
4. 자동화 & 보관 정책
5. 복구 방법
6. USB 외부 백업
7. 주의사항 & 팁
8. 백업 검증
1. 백업 대상
📦 PostgreSQL 컨테이너
my-app-db-prod
my-app-db-dev
my-site-db
my-service-db-dev
📦 MySQL 컨테이너
my-mysql-01
my-mysql-02
📦 Docker Volumes
project_a_db_data
project_a_wordpress_data
my-app-infra_postgres_data_dev
my-app-infra_redis_data_dev
my-app_backups
my-app_postgres_data
my-app_redis_data
my-app_uploads
other-app_postgres_dev_data
my-site_postgres_data
nextcloud_data
project_b_db_data
project_b_wordpress_data
👉 특히 nextcloud_data, my-app_uploads, wordpress_data 는 파일데이터라 반드시 백업 필요.
📦 백업 전략 요약
항목 | 이유 | 백업 방식 |
|---|---|---|
DB (PostgreSQL / MySQL) | 논리백업 필수 — Volume 복사만으로는 깨질 수 있음 |
|
Docker Volume | 실제 서비스 데이터 저장 위치 | Alpine 임시 컨테이너 + tar |
Docker 메타정보 | 컨테이너 설정 / 네트워크 / 이미지 목록 |
|
사용자 파일 | docker-compose, nginx, SSL 인증서 등 |
|
Docker 이미지 | 다시 pull 가능 → 백업 불필요 | 제외 |
2. 통합 백업 스크립트
📄 /root/docker-full-backup.sh — 이 스크립트 하나로 전체 백업을 수행합니다.
#!/bin/bash
set -e
DATE=$(date +%F-%H%M)
BASE="/backup/$DATE"
echo "=================================================="
echo " Docker Full Backup Start : $DATE"
echo "=================================================="
mkdir -p $BASE/{postgres,mysql,volumes,meta}
########################################
# 1️⃣ PostgreSQL Logical Backup
########################################
echo "[1/5] Backing up PostgreSQL..."
PG_CONTAINERS=(
my-app-db-prod
my-app-db-dev
my-site-db
my-service-db-dev
)
for C in "${PG_CONTAINERS[@]}"; do
echo " -> Processing $C"
PGUSER=$(docker inspect $C \
| grep POSTGRES_USER \
| head -n1 \
| cut -d= -f2 \
| tr -d '",')
if [ -z "$PGUSER" ]; then
echo " ERROR: POSTGRES_USER not found in $C"
exit 1
fi
echo " Using DB User: $PGUSER"
docker exec $C pg_dumpall -U "$PGUSER" \
> $BASE/postgres/$C.sql
done
echo " PostgreSQL backup completed."
########################################
# 2️⃣ MySQL Logical Backup
########################################
echo "[2/5] Backing up MySQL..."
docker exec my-mysql-01 mysqldump -uroot -p$MYSQL_ROOT_PASSWORD --all-databases \
> $BASE/mysql/my-mysql-01.sql
docker exec my-mysql-02 mysqldump -uroot -p$MYSQL_ROOT_PASSWORD --all-databases \
> $BASE/mysql/my-mysql-02.sql
echo " MySQL backup completed."
########################################
# 3️⃣ Docker Volume Backup
########################################
echo "[3/5] Backing up Docker Volumes..."
for VOLUME in $(docker volume ls -q); do
echo " -> $VOLUME"
docker run --rm \
-v ${VOLUME}:/volume \
-v $BASE/volumes:/backup \
alpine \
tar czf /backup/${VOLUME}.tar.gz -C /volume .
done
echo " Volume backup completed."
########################################
# 4️⃣ Docker Metadata Backup
########################################
echo "[4/5] Saving Docker metadata..."
docker ps -a > $BASE/meta/container-list.txt
docker inspect $(docker ps -aq) > $BASE/meta/docker-inspect.json
docker volume ls > $BASE/meta/volume-list.txt
docker network ls > $BASE/meta/network-list.txt
docker images > $BASE/meta/image-list.txt
echo " Metadata backup completed."
########################################
# 5️⃣ Project Files Backup
########################################
echo "[5/5] Backing up /home/your-user ..."
tar czf $BASE/meta/home-backup.tar.gz /home/your-user
echo " Project files backup completed."
########################################
echo "=================================================="
echo " Docker Full Backup SUCCESS : $BASE"
echo "=================================================="
########################################
# 6️⃣ Remove Old Backups (30일 보관)
########################################
echo "Cleaning backups older than 30 days..."
find /backup -mindepth 1 -maxdepth 1 -type d -mtime +30 -exec rm -rf {} \;
echo "Old backup cleanup completed."3. 설정 & 실행
3-1. 디렉토리 & 권한 설정
sudo mkdir /backup
sudo chmod 700 /backup
sudo nano /root/docker-full-backup.sh
sudo chmod +x /root/docker-full-backup.sh
3-2. 수동 테스트 실행
sudo /root/docker-full-backup.sh
3-3. 실행 결과 확인
ls /backup
예시 결과:
/backup/YYYY-MM-DD-HHMM/
├── postgres/
├── mysql/
├── volumes/
└── meta/
4. 자동화 & 보관 정책
4-1. cron 자동 백업 (매일 새벽 3시)
sudo crontab -e
아래 줄 추가:
0 3 * * * /root/docker-full-backup.sh >> /var/log/docker-backup.log 2>&1
4-2. 보관 정책 (30일)
스크립트 내에 아래 명령이 포함되어 있어 30일 지난 백업은 자동 삭제됩니다.
find /backup -mindepth 1 -maxdepth 1 -type d -mtime +30 -exec rm -rf {} \;4-3. (선택) 월 1회 스냅샷 백업
재해복구용 Docker 엔진 전체 백업입니다. 짧은 다운타임이 발생합니다.
sudo systemctl stop docker
sudo tar --xattrs --acls -czvf /backup/docker-engine-$(date +%F).tar.gz /var/lib/docker
sudo systemctl start docker
👉 매일 할 필요 없으며, 월 1회면 충분합니다.
5. 복구 방법
새 서버에서 아래 순서로 복구합니다.
5-1. Docker 설치
공식 문서를 참고하여 Docker Engine을 설치합니다.
5-2. 백업 폴더 복사
USB 등에서 /backup/YYYY-MM-DD-HHMM 폴더를 서버로 복사합니다.
5-3. PostgreSQL 복구
cat my-app-db-prod.sql | docker exec -i my-app-db-prod psql -U postgres
5-4. MySQL 복구
cat my-mysql-01.sql | docker exec -i my-mysql-01 mysql -uroot -p
5-5. Volume 복구
docker run --rm -v nextcloud_data:/volume -v $(pwd):/backup alpine \
tar xzf /backup/nextcloud_data.tar.gz -C /volume
6. USB 외부 백업
백업 폴더를 USB 외장 매체로 안전하게 복사하는 절차입니다. (Ubuntu 24.04 기준)
6-1. USB 장치 확인
lsblk
예시 출력:
sda 8:0 0 1.8T 0 disk
├─sda1 8:1 0 512M 0 part
└─sda2 8:2 0 1.8T 0 part
sdb 8:16 1 58G 0 disk <-- ★ USB
└─sdb1 8:17 1 58G 0 part
👉 USB는 보통 sdb 또는 sdc 로 잡히며, sdb1 같은 파티션 이름을 사용합니다.
6-2. USB 마운트
sudo mkdir -p /mnt/usb
sudo mount /dev/sdb1 /mnt/usb
6-3. 마운트 확인
df -h | grep usb
# 또는
ls /mnt/usb
6-4. rsync로 복사 (필수)
절대 cp 명령을 쓰지 마세요. 권한이 깨집니다.
Docker / DB 백업은 반드시 rsync를 사용합니다.
sudo rsync -avh /backup/YYYY-MM-DD-HHMM /mnt/usb/
옵션 | 의미 |
|---|---|
| 권한 / 소유자 / 심볼릭 링크 유지 (★ 핵심) |
| 진행상황 표시 |
| 사람이 읽기 쉬운 용량 표시 |
다음 속성이 그대로 유지됩니다: root 권한, Docker volume 권한, DB 데이터 권한, tar 파일 속성, UID/GID, 심볼릭 링크
6-5. 복사 검증
du -sh /backup/YYYY-MM-DD-HHMM
du -sh /mnt/usb/YYYY-MM-DD-HHMM
두 값이 같으면 성공입니다.
6-6. 안전한 USB 제거
sync
sudo umount /mnt/usb
이후 USB를 물리적으로 분리합니다.
7. 주의사항 & 팁
🔥 절대 하면 안 되는 실수
cp -r /backup/... # ❌ 권한 깨짐
mv /backup/... # ❌ 원본 사라짐
tar 다시 묶기 # ❌ Docker 복구 실패 위험
Docker volume 백업 복사는 rsync만 사용하세요.
💡 tar 경고 메시지는 정상
tar: socket ignored
DBUS 소켓, 캐시 파일 등 런타임 전용 파일이라 무시해도 됩니다.
💡 Alpine 이미지 다운로드 메시지도 정상
Unable to find image 'alpine:latest'
Volume을 안전하게 읽기 위해 임시 Alpine 컨테이너를 띄우는 정석 방식입니다.
8. 백업 검증
📦 백업 폴더 구조
/backup/YYYY-MM-DD-HHMM/
├── postgres/ # PostgreSQL dump (.sql)
├── mysql/ # MySQL dump (.sql)
├── docker_volumes/ # 모든 Docker Volume tar.gz
├── metadata/ # 컨테이너/네트워크/이미지 목록
└── home_backup.tar # 사용자 프로젝트 파일
👉 이 폴더 하나만 있으면 서버 전체 복구가 가능합니다.
🔎 복구 테스트 (권장)
백업 검증의 핵심은 "복구 테스트"입니다.
빈 테스트 서버 준비
Docker 설치
백업 폴더 복사
Volume 복원 후 컨테이너 실행
→ 서비스가 정상 기동되면 백업 100% 성공입니다.
✅ 요약
✔ DB: pg_dumpall / mysqldump 논리 백업 — 운영 중에도 안전
✔ Volume: Alpine 임시 컨테이너로 tar 압축 — 데이터 무결성 보장
✔ 메타데이터: 컨테이너 설정 전체 기록
✔ 프로젝트 파일: /home 전체 보존
✔ 30일 자동 정리 + cron 자동화
✔ USB 외부 복사는 rsync -avh 만 사용
👉 이 가이드를 따르면 Docker 환경을 완전히 복구할 수 있는 실전형 백업이 완성됩니다.
